周精益分享 - 前端入门篇2期

博客地址

Swift柯里化 Curring 学习

什么是Curring

维基百科解释
在计算机科学中,柯里化(英语:Currying),又译为卡瑞化或加里化,是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数,并且返回接受余下的参数而且返回结果的新函数的技术。

概念看上去还是有点抽象,直接看代码

例子
注:所有swift代码都可以放到playgroun中运行查看输出

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import UIKit

// 一个普通求sum函数
func add(a: Int, b: Int, c: Int) -> Int{
print("\(a) + \(b) + \(c) = \(a + b + c)")
return a + b + c
}

add(1, b: 2,c: 3) // 打印1 + 2 + 3 = 6

// 柯里化版本的求sum函数
func addCur(a: Int)(b: Int)(c: Int) -> Int{
print("\(a) + \(b) + \(c) = \(a + b + c)")
return a + b + c
}

addCur(1)(b: 2)(c: 3) // 打印1 + 2 + 3 = 6

你也许觉得Curring只是用一个特殊的写法
其他与普通函数无异
那么换一种curring的调用方式

1
2
3
4
5
6
7
8
9
10
// curring 另类调用方式
let funcWithA = addCur(1)
print("funcWithA type : \(funcWithA.dynamicType)")
let funcWithAB = funcWithA(b: 2)
print("funcWithAB type : \(funcWithAB.dynamicType)")
let resultCurring = funcWithAB(c: 3)
print("resultCurring type : \(resultCurring.dynamicType)")
```

此时你还是会觉得这只是把一个函数拆开来调用了 那么我们打印一下 每个调用步骤中变量的类型

let funcWithA = addCur(1)
print(“funcWithA type : (funcWithA.dynamicType)”) //
let funcWithAB = funcWithA(b: 2)
print(“funcWithAB type : (funcWithAB.dynamicType)”)
let resultCurring = funcWithAB(c: 3)
print(“resultCurring type : (resultCurring.dynamicType)”)

1
2

打印结果为

1 + 2 + 3 = 6
funcWithA type : Int -> Int -> Int
funcWithAB type : Int -> Int
1 + 2 + 3 = 6
resultCurring type : Int

1
2
3
4
5
6
7
8
9
10
11
12
13

可以看到 变量funcWithA 为 Int -> Int -> Int 类型
funcWithAB 为Int -> Int

这说明 curring函数在绑定最后一个参数之前 每个步骤返回的值都是一个函数

###Curring实现原理

Swift实现Curring的基础有两个
- 函数是一级公民
- 闭包

[啊崢的Swift Curring文章](http://www.jianshu.com/p/6eaacadafa1a)代码例子解释的已经很清楚了

class Currying
{
/ uncurried:普通函数 /
// 接收多个参数的函数
func add(a: Int, b: Int, c: Int) -> Int{
println(“(a) + (b) + (c)”)
return a + b + c
}

/*** 手动实现柯里化函数 ***/
// 把上面的函数转换为柯里化函数,首先转成接收第一个参数a,并且返回接收余下第一个参数b的新函数(采用闭包)
// 为了让大家都能看懂,我帮你们拆解来看下
// (a: Int) : 参数
// (b:Int) -> (c: Int) -> Int : 函数返回值(一个接收参数b的函数,并且这个函数又返回一个接收参数c,返回值为Int类型的函数)

// 定义一个接收参数a,并且返回一个接收参数b的函数,并且这个函数又返回一个接收参数c,返回值为Int类型的函数
func add(a: Int) -> (b:Int) -> (c: Int) -> Int{

    // 一个接收参数b的函数,并且这个函数又返回一个接收参数c,返回值为Int类型的函数
    return { (b:Int) -> (c: Int) -> Int in

        // 返回一个接收余下第一个参数c,并且有返回结果为Int类型的函数
        return { (c: Int) -> Int in

            return a + b + c;

 注解: 这里为什么能使用参数a,b,c?
       利用闭包的值捕获特性,即使这些值作用域不在了,也可以捕获到他们的值。
       闭包会自动判断捕获的值是值拷贝还是值引用,如果修改了,就是值引用,否则值拷贝。

       注意只有在闭包中才可以,a,b,c都在闭包中。

        }

    }

}


/*** curried: 系统自带的柯里化函数 ***/
func addCur(a: Int)(b: Int)(c: Int) -> Int{
    println("\(a) + \(b) + \(c)")
    return a + b + c
}

}

1
2
3
4

###OC版的Curring

大部分的iOS程序员都还是习惯写OC 找了一个[OC版本的Curring](https://gist.github.com/lukhnos/1771842)实现 我们可以理解的更深刻

include

int f(int x, int y)
{
return x + y;
}

int main()
{
// 闭包1 绑定第一个参数
typedef int (^int_to_int_t)(int);
// 闭包2 绑定第二个参数
typedef int_to_int_t (^int_to_int_to_int_t)(int);

int_to_int_to_int_t h = ^(int x) {
    int_to_int_t g = ^(int y) {
        // 将两个闭包持有的参数做处理 返回结果
        return f(x, y);  
    };

    return g;        
};

// 第一个闭包持有 5
int_to_int_t g = h(5);

int z;
// 第二个闭包持有10 并返回结果
z = g(10);
printf("%d\n", z);

}

1
2
3
4
5
6
7
8
9
10
11
12

###什么?你觉得然并卵!

你一定觉得这是一个然并卵的东西

好吧 我第一个看到的时候 只是觉得有趣 其实也没有想到较好的应用场景

[为什么要柯里化](https://gist.github.com/jcouyang/b56a830cd55bd230049f)这篇文章提供的例子给了很多启发

用Swift重新实现了一遍 又加了一点打印 豁然开朗

上代码

// 拼接字符
func concat(chars: Array) {
var resultString = “”
for char in chars {
resultString += char
}
print(resultString)
}

concat([“1”,”2”,”3”])
print(“**“)

// 每个字符代表的数字 + 1 后再拼接
func concatAdd(chars: Array, addNum: Int) {
var resultString = “”
for char in chars {
var num = Int(char)!
num = num + addNum
let newChar = String(num)
resultString += newChar
}
print(resultString)
}

concatAdd([“1”,”2”,”3”], addNum: 1)
concatAdd([“1”,”2”,”3”], addNum: 2)
concatAdd([“1”,”2”,”3”], addNum: 3)

print(“**“)
// 每个字符代表的数字 10 后再拼接
func concatMultiply(chars: Array, multiplyNum: Int) {
var resultString = “”
for char in chars {
var num = Int(char)!
num = num
multiplyNum
let newChar = String(num)
resultString += newChar
}
print(resultString)
}

concatMultiply([“1”,”2”,”3”], multiplyNum: 1)
concatMultiply([“1”,”2”,”3”], multiplyNum: 2)
concatMultiply([“1”,”2”,”3”], multiplyNum: 3)

print(“**“)
/
让我们使用柯里化吧
*
/
func add(a: Int)(b: Int) -> Int{
return a + b
}

func multiply(a: Int)(b: Int) -> Int{
return a * b
}

func concatByCurring(chars: Array)(caculateFunc: (Int)->Int) {
var resultString = “”
for char in chars {
var num = Int(char)!
var newNum = caculateFunc(num)
let newChar = String(newNum)
resultString += newChar
}
print(resultString)
}

concatByCurring([“1”,”2”,”3”])(caculateFunc: add(1))
concatByCurring([“1”,”2”,”3”])(caculateFunc: add(2))
concatByCurring([“1”,”2”,”3”])(caculateFunc: add(3))

print(“**“)
concatByCurring([“1”,”2”,”3”])(caculateFunc: multiply(1))
concatByCurring([“1”,”2”,”3”])(caculateFunc: multiply(2))
concatByCurring([“1”,”2”,”3”])(caculateFunc: multiply(3))

1
2
3
4
5
6
7
8
9
10
11
12
13
14

以上的代码用普通的函数 和 Curring函数 处理了同一个功能

Curring优势明显
- 重用了拼接代码
- 支持更为灵活的算法替换
- 写功能扩展的人不用怎么关心老代码的实现

###iOS开发中可以应用的场景

**使用Curring处理selector**
这个例子是我在看[王巍的Swifter](https://selfstore.io/~onevcat)时候看到的一个例子

不废话 直接上代码

// 打印func类型
class People: NSObject {
func speak(){
print(“hello”)
}

func printSpeak() {
    print("People func speak  : \(People.speak.dynamicType)")
}

}

People().printSpeak()
// 打印结果为 People func speak : People -> () -> ()
// 可见实例的方法就是一个Curring结构

1
2

下面是[Instance Methods are Curried Functions in Swift](http://oleb.net/blog/2014/07/swift-instance-methods-curried-functions/?utm_campaign=iOS_Dev_Weekly_Issue_157&utm_medium=email&utm_source=iOS%2BDev%2BWeekly)中的例子 很开脑洞

//Selector demo
protocol TargetAction {
func performAction()
}

struct TargetActionWrapper : TargetAction {
weak var target: T?

// 此处的action类型是不是和我上面代码中打印的结构一致
let action: (T) -> () -> ()

func performAction() -> () {
    if let t = target {
        // Curring调用
        action(t)()
    }
}

}

enum ControlEvent {
case TouchUpInside
case ValueChanged
}

class Control {
var actions = ControlEvent: TargetAction

func setTarget<T: AnyObject>(target: T, action: (T) -> () -> (), controlEvent: ControlEvent) {
    actions[controlEvent] = TargetActionWrapper(target: target, action: action)
}

func removeTargetForControlEvent(controlEvent: ControlEvent) {
    actions[controlEvent] = nil
}

func performActionForControlEvent(controlEvent: ControlEvent) {
    actions[controlEvent]?.performAction()
}

}

class MyViewController {
let button = Control()

func viewDidLoad() {
    button.setTarget(self, action: MyViewController.onButtonTap, controlEvent: .TouchUpInside)
}

func onButtonTap() {
    print("Button was tapped")
}

}

// 调用
MyViewController().onButtonTap()

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48

###小结
- Curring让计算过程更清晰 函数式编程的有点初见端倪
- Curring让计算过程更独立 可重用
- Curring让计算功能扩展更方便
- Curring让Swift中Selector的重构可以实现



## Umeng分享遇到的小坑 -- 张超耀
### 写在前面的话
- 在iOS9下,系统默认会拦截对http协议接口的访问,因此无法获取http协议接口的数据。对Umeng来说,具体表现可能是,无法授权、分享、获取用户信息等。
- iOS9新建项目默认需要支持bitcode,而不支持bitcode的SDK会导致无法编译运行。[App Thining](https://developer.apple.com/library/ios/documentation/IDEs/Conceptual/AppDistributionGuide/AppThinning/AppThinning.html#//apple_ref/doc/uid/TP40012582-CH35))

[Umeng适配iOS9](http://dev.umeng.com/social/ios/ios9)

### 针对iOS9的Https特性,解决方案
- Plan A: 暂时退回到http协议:

>**1**、在项目的info.plist中添加一个Key:NSAppTransportSecurity,类型为字典类型。
>**2**、然后给它添加一个Key:NSAllowsArbitraryLoads,类型为Boolean类型,值为YES;

- Plan B:设置域。可以简单理解成,把不支持https协议的接口设置成http的接口


>**1**、在项目的info.plist中添加一个Key:NSAppTransportSecurity,类型为字典类型。

>**2**、然后给它添加一个NSExceptionDomains,类型为字典类型;

>**3**、把需要的支持的域添加給NSExceptionDomains。其中域作为Key,类型为字典类型。

>**4**、每个域下面需要设置3个属性:NSIncludesSubdomains、 NSExceptionRequiresForwardSecrecy、 NSExceptionAllowsInsecureHTTPLoads。
均为Boolean类型,值分别为YES、NO、YES。

### 针对App Thinning

### 添加Scheme白名单实现应用跳转(SSO等)
- 问题描述:在iOS 9下涉及到平台客户端跳转,系统会自动到项目info.plist下检测是否设置平台Scheme。对于需要配置的平台,如果没有配置,就无法正常跳转平台客户端。因此要支持客户端的分享和授权等,需要配置Scheme名单。
- 解决方案:

具体方法:
>1、在项目的info.plist中添加一LSApplicationQueriesSchemes,类型为Array。

>2、然后给它添加一个需要支持的项目,类型为字符串类型


### 注意
- 由于苹果审核政策需求,需要对未安装客户端平台进行隐藏,在设置QQ、微信AppID之后调用下面的方法,

[UMSocialConfig hiddenNotInstallPlatforms:@[UMShareToQQ, UMShareToQzone, UMShareToWechatSession, UMShareToWechatTimeline]];

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
 - but  这个接口只对默认分享面板平台有隐藏功能,自定义分享面板或登录按钮需要自己处理

- 对于自定义分享面板处理:
- UmengSDK已经嵌入相关API,直接用就好

### 只要按照官方文档来,基本上就能马到成功()



##MarkDown 的 CSS 实现配置 - 杨志平

####题目灵感来源
> 起源于我们现有的博客引擎主题交互很不错,但是排版烂的要死 ,我水平有限这里只是浅显介绍实现修改我们的markdown编译器的一些排版样式

#### 研究方向
> 自定义一个非标准化,有其他多元素的MarkDown解析器 如下几点:

- 可选框
`- [ ] `
- 本地图片索引,可控制对齐及大小
`![Alt text](http://path/to/img.jpg "optional title" 100x200)`
`![Alt text](./1449756974449.png)`
- 标签功能
`@(Share)[css, Markdown]`
- 代码高亮(不同语言)

`swift`

``` swift
private var majorModel = PickMajorModel()
private var subjectModel = OFFKeyNameModel()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}

objectivec

1
2
3
UIScrollView *scrollView = [[UIScrollView alloc] initWithFrame:CGRectMake(0, 0, kScreenW, kScreenH)];
scrollView.showsVerticalScrollIndicator = NO;
[scrollView addSubview:self.downMainView];

有一种惨不忍睹的即视感
Alt text

MarkDown来源及实现

Markdown is a plain text format for writing structured documents, based on conventions used for indicating formatting in email and usenet posts. It was developed in 2004 by John Gruber, who wrote the first markdown-to-html converter in Perl, and it soon became widely used in websites. By 2014 there were dozens of implementations in many languages.

见知乎上回答
实现一个markdown解析器需要具备那些知识

如何简单的改善文字编排的效果

更换博客主题(简单粗暴)

我们使用的博客引擎Hexo来举例,列举下面三个主题

  • landscape
  • hexo-theme-vno-master
  • hexo-theme-yilia-master
更换MarkDown编译器的主题

Mou 举例子,它提供了多套markdown语法下的排版样式
手动新创建一个CSS文本布局配置 Blog
Alt text

CSS配置文件修改

详细配置参数如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
html { font-size: 62.5%; }
html, body { height: 100%; }

body {
font-family: Helvetica, Arial, sans-serif;
font-size: 150%;
line-height: 1.3;
color: #f6e6cc;
width: 700px;
margin: auto;
background: #27221a;
position: relative;
padding: 0 30px;
}

多级标题配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
h1 {
font-size: 28px;
color: black; }


h2 {
font-size: 24px;
border-bottom: 1px solid #cccccc;
color: black; }


h3 {
font-size: 18px; }


h4 {
font-size: 16px; }


h5 {
font-size: 14px; }


h6 {
color: #777777;
font-size: 14px; }

表格

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
table {
padding: 0;border-collapse: collapse; }

table tr {
border-top: 1px solid #cccccc;
background-color: white;
margin: 0;
padding: 0; }

table tr:nth-child(2n) {
background-color: #f8f8f8
; }

table tr th {
font-weight: bold;
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }

table tr td {
border: 1px solid #cccccc;
margin: 0;
padding: 6px 13px; }

table tr th :first-child, table tr td :first-child {
margin-top: 0
; }

table tr th :last-child, table tr td :last-child {
margin-bottom: 0
; }

代码高亮

1
2
3
4
5
6
7
8
9
10
11
12
13
14
code, tt {
margin: 0 2px;
padding: 0 5px;
white-space: nowrap;
border: 1px solid #eaeaea;
background-color: #f8f8f8;
border-radius: 3px; }


pre code {
margin: 0;
padding: 0;
white-space: pre;
border: none;
background: transparent; }